#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <strings.h>

#include <iostream>
#include <string>
#include <sys/stat.h>
#include <sys/time.h>
#include <pthread.h>
#include "definitions.hpp"

using namespace std;

string filename; //Please fix this, its only temporary

FILE *fp;

//Global Declarations of Locks begin ------------------------------->

     pthread_mutex_t synch_lock;
     pthread_cond_t wakeup_udp;

     pthread_mutex_t dup_lock;
     pthread_cond_t dup_cond;   
     pthread_mutex_t chunk_lock;


//Global Declarations of Locks end --------------------------------->
unsigned char dupBuffer1[2500];
int complete_flag=0;

Data* d1;


int sock_ready_client(int sock)
{
    int             res;
    fd_set          sready;
    struct timeval  nowait;
    
    nowait.tv_usec=100;
    FD_ZERO(&sready);
    FD_SET((unsigned int)sock,&sready);
    
    memset((char *)&nowait,0,sizeof(nowait));
    
    
    res = select(sock+1,&sready,NULL,NULL,&nowait);
    if( FD_ISSET(sock,&sready) )
        res = 1;
    else
        res = 0;
    
    return(res);
}

void error(const char *msg)
{
    perror(msg);
    exit(0);
}


    
double mytime(void)
{
    struct timeval tv;
    double currtime=0;
    gettimeofday(&tv,NULL);
    currtime=((double)(tv.tv_sec)*1000.0) + ((double)(tv.tv_usec)/1000.0);
    return currtime;
}
    
    int main(int argc, char *argv[])
    {

		

	 //Initializing Locks Begin-------------------------------------------------->

     pthread_mutex_init(&synch_lock,NULL);
     pthread_cond_init(&wakeup_udp,NULL);
     pthread_mutex_init(&dup_lock,NULL);
	 pthread_mutex_init(&chunk_lock,NULL);
	 pthread_cond_init(&dup_cond,NULL);

     


	 //Initializing Locks End---------------------------------------------------->
        
        
        
        if (argc < 3) {
            fprintf(stderr,"usage %s hostname port\n", argv[0]);
            exit(0);
        }
        
        // Get the file name from the command line
        
        filename = string(argv[3]);
        cout<<"filename "<<filename<<endl;
        
        fp = fopen(filename.c_str(),"r");
        
        if(fp == NULL){
            cerr<<"File can not be opened"<<endl;
            exit(1);
        }else{
            
            // Begin obtaining file details
            struct stat sb;
            lstat(filename.c_str(),&sb);
            uint64_t fsize = sb.st_size;
            cout<<"filesize "<<fsize<<endl;
            //
            
            // BEGIN TCP thread here ----------------------------------->
            
            string hname = string(argv[1]);
            int portno = atoi(argv[2]);
            
            d1 = new Data(hname,portno,fsize,fp);
            // cout<<d1->getPortNum()<<d1->getHostname()<<endl;
            pthread_t tcp_thread;
            pthread_attr_t attr_tcp;
            int thrd_tcp=0;
            void* status_tcp;
            
            pthread_attr_init(&attr_tcp);
            pthread_attr_setdetachstate(&attr_tcp, PTHREAD_CREATE_JOINABLE);
            
            thrd_tcp=pthread_create(&tcp_thread,&attr_tcp,tcp_thread_client_func,(void *)d1);
            if(thrd_tcp){
                cerr<<"Error; return code from thread tcp create call is"<<thrd_tcp<<endl;
                exit(-1);
            } 
            
            pthread_attr_destroy(&attr_tcp);
            
                       
          
            // END TCP thread here ----------------------------------->
            
            
            // BEGIN UDP thread here ----------------------------------->
            
            pthread_t udp_thread;
            pthread_attr_t attr_udp;
            int thrd_udp=0;
            void* status_udp;
            
            pthread_attr_init(&attr_udp);
            pthread_attr_setdetachstate(&attr_udp, PTHREAD_CREATE_JOINABLE);
            
            thrd_udp=pthread_create(&udp_thread,&attr_udp,udp_thread_client_func,(void *)d1);
            if(thrd_udp){
                cerr<<"Error; return code from thread tcp create call is"<<thrd_udp<<endl;
                exit(-1);
            } 
            
            pthread_attr_destroy(&attr_udp);
            
            
            thrd_udp=pthread_join(udp_thread,&status_udp);
            if(thrd_udp){
                cerr<<"Error; return code from thread tcp join call is "<<thrd_udp<<endl;
                exit(-1);
            }

			thrd_tcp=pthread_join(tcp_thread,&status_tcp);
            if(thrd_tcp){
                cerr<<"Error; return code from thread tcp join call is "<<thrd_tcp<<endl;
                exit(-1);
            }
            
            // END UDP thread here ----------------------------------->
        }
		//Begin Destroy Locks and CVs ------------------------------------------->
     pthread_mutex_destroy(&synch_lock);
	 pthread_mutex_destroy(&dup_lock);
     pthread_mutex_destroy(&chunk_lock);
	 pthread_cond_destroy(&wakeup_udp);
	 pthread_cond_destroy(&dup_cond);
	 //End Destroy Locks and CVs --------------------------------------------->
        
        fclose(fp);


        return 0;
    }
